package com.eastfair.imaster.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.annotation.base.LanguageTypeEnum;
import com.eastfair.annotation.base.SubjectTypeEnum;
import com.eastfair.api.NoticeServiceFeign;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.core.utils.DateUtils;
import com.eastfair.enums.*;
import com.eastfair.imaster.dao.AppointmentMapper;
import com.eastfair.imaster.dto.AppointmentDTO;
import com.eastfair.imaster.entity.Appointment;
import com.eastfair.imaster.service.AppointmentService;
import com.eastfair.notice.dto.MsgFieldDTO;
import com.eastfair.notice.dto.MsgSendDTO;
import com.eastfair.notice.dto.MsgSendTypeDTO;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 业务实现类
 * 邀约
 * </p>
 *
 * @author liuxiaobai
 * @date 2021-09-02
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class AppointmentServiceImpl extends SuperServiceImpl<AppointmentMapper, Appointment> implements AppointmentService {
    @Autowired
    private ProjectCoreServiceFeign projectCoreServiceFeign;
    @Autowired
    private NoticeServiceFeign noticeServiceFeign;

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(Appointment entity) {
        UpdateWrapper<Appointment> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(Appointment::getProjectId, ContextUtil.getProjectId()).eq(Appointment::getId, entity.getId());
        entity.setProjectId(null);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    @Override
    public R<Boolean> launchBatch(AppointmentDTO appointmentDTO) {
        MsgSendDTO msgSendDTO = MsgSendDTO.builder()
                .languageType(LanguageTypeEnum.parse(ContextUtil.getLanguageType()))
                .subjectType(SubjectTypeEnum.APPOINTMENT)
                .noticeType(NoticeTypeEnum.APPOINTMENT)
                .build();
        if (SubjectTypeEnum.ACTOR.name().equals(ContextUtil.getSubjectType())) {
            //todo 获取当前登录人展商ID

            return launchBatchExhibitor(appointmentDTO, msgSendDTO);
        }
        //当前登录观众ID
        appointmentDTO.setVisitorUserId(ContextUtil.getUserId());
        return launchBatchVisitor(appointmentDTO, msgSendDTO);
    }

    @Override
    public Boolean updateStatus(AppointmentDTO appointmentDTO) {
        Appointment appointment = Appointment.builder()
                .id(appointmentDTO.getId())
                .status(appointmentDTO.getStatus())
                .reason(appointmentDTO.getReason())
                .build();
        return updateByIdOfShard(appointment);
    }

    /**
     * 展商发起 展商邀观众
     *
     * @return R
     */
    private R<Boolean> launchBatchExhibitor(AppointmentDTO appointmentDTO, MsgSendDTO msgSendDTO) {
        //当前登录人为展商 则通知接收人为观众
        msgSendDTO.setReceiveType(SubjectTypeEnum.VISITOR);
        msgSendDTO.setSendTypes(Arrays.asList(
                MsgSendTypeDTO.builder().msgTypeEnum(MsgTypeEnum.SMS).msgTempEnum(MsgTempEnum.APPOINTMENT_VISITOR_PENDING).build(),
                MsgSendTypeDTO.builder().msgTypeEnum(MsgTypeEnum.EMAIL).msgTempEnum(MsgTempEnum.APPOINTMENT_VISITOR_PENDING).build(),
                MsgSendTypeDTO.builder().msgTypeEnum(MsgTypeEnum.NOTICE).msgTempEnum(MsgTempEnum.APPOINTMENT_VISITOR_PENDING).build()
        ));
        //校验重复邀约
        if (checkAppointmentBatch(appointmentDTO)) {
            return R.fail(ExceptionCode.APPOINTMENT_REPEAT);
        }
        Long projectId = ContextUtil.getProjectId();
        List<Appointment> batchInsertList = new ArrayList<>(appointmentDTO.getReceiveIds().size());
        List<MsgSendDTO> msgSends = new ArrayList<>(appointmentDTO.getReceiveIds().size());
        //批量处理 set观众ID
        appointmentDTO.getReceiveIds().forEach(visitorUserId -> {
            Appointment appointment = BeanUtil.copyProperties(appointmentDTO, Appointment.class);
            appointment.setId(DefaultUidGenerator.getUidOfProjectId(projectId));
            appointment.setVisitorUserId(visitorUserId);
            batchInsertList.add(appointment);

            MsgSendDTO send = BeanUtil.copyProperties(msgSendDTO, MsgSendDTO.class);
            send.setBusinessId(appointment.getId());
            send.setReceiveUserId(visitorUserId);
            //todo 通过用户ID获取手机号邮箱姓名公司等
            //send.setEmail();
            //send.setMobile();
            send.setFields(Arrays.asList(
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.VISITOR_NAME_CN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.VISITOR_NAME_EN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.EXHIBITOR_NAME_CN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.EXHIBITOR_NAME_EN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.EXHIBITOR_EMPLOYEE_NAME_CN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.EXHIBITOR_EMPLOYEE_NAME_EN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.APPOINTMENT_TIME).value(DateUtils.format(appointment.getStartTime(), DateUtils.DEFAULT_DATE_TIME_FORMAT)).build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.EXHIBITION_NAME_CN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.EXHIBITION_NAME_EN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.APPOINTMENT_PLACE_CN).value("").build(),
                    MsgFieldDTO.builder().fieldEnum(MsgFieldEnum.APPOINTMENT_PLACE_EN).value("").build()
            ));
            msgSends.add(send);
        });
        super.saveBatch(batchInsertList);
        this.noticeServiceFeign.sendBatch(msgSends);
        return R.success();
    }

    /**
     * 观众发起 观众邀展商
     *
     * @return R
     */
    private R<Boolean> launchBatchVisitor(AppointmentDTO appointmentDTO, MsgSendDTO msgSendDTO) {
        //当前登录人为观众 则通知接收人为展商
        msgSendDTO.setReceiveType(SubjectTypeEnum.ACTOR);

        //校验重复邀约
        if (checkAppointmentBatch(appointmentDTO)) {
            return R.fail(ExceptionCode.APPOINTMENT_REPEAT);
        }
        Long projectId = ContextUtil.getProjectId();
        List<Appointment> batchInsertList = new ArrayList<>(appointmentDTO.getReceiveIds().size());
        //批量处理 set展商ID
        appointmentDTO.getReceiveIds().forEach(exhibitorId -> {
            Appointment appointment = BeanUtil.copyProperties(appointmentDTO, Appointment.class);
            appointment.setId(DefaultUidGenerator.getUidOfProjectId(projectId));
            appointment.setExhibitorId(exhibitorId);
            batchInsertList.add(appointment);
            //todo 获取展商所有员工 要给每个员工发通知
        });
        super.saveBatch(batchInsertList);
        return R.success();
    }

    /**
     * 批量校验是否已经邀约过
     *
     * @param appointmentDTO exhibitorId、visitorUserId、receiveIds
     * @return 有一条邀约过即返回false 全部没邀约过返回true
     */
    private Boolean checkAppointmentBatch(AppointmentDTO appointmentDTO) {
        QueryWrapper<Appointment> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Appointment::getProjectId, ContextUtil.getProjectId())
                .eq(Appointment::getExhibitionId, ContextUtil.getExhibitionId())
                .ne(Appointment::getStatus, AuditStateEnum.DISAPPROVE)
                .eq(Appointment::getIsDelete, BusinessConstant.DELETE_NO);
        if (SubjectTypeEnum.ACTOR.name().equals(ContextUtil.getSubjectType())) {
            queryWrapper.lambda()
                    .eq(Appointment::getExhibitorId, appointmentDTO.getExhibitorId())
                    .in(Appointment::getVisitorUserId, appointmentDTO.getReceiveIds());
        } else {
            queryWrapper.lambda()
                    .eq(Appointment::getVisitorUserId, appointmentDTO.getVisitorUserId())
                    .in(Appointment::getExhibitorId, appointmentDTO.getReceiveIds());
        }
        return super.count(queryWrapper) > 0;
    }
}
